package com.ruicar.afs.cloud.workflow.greatwall.processor.impl.objcode;

import cn.hutool.core.thread.ThreadUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruicar.afs.cloud.admin.api.feign.AfsRoleFeign;
import com.ruicar.afs.cloud.common.core.constant.CommonConstants;
import com.ruicar.afs.cloud.common.core.constant.SecurityConstants;
import com.ruicar.afs.cloud.common.core.dynamicrequest.DynamicRequest;
import com.ruicar.afs.cloud.common.core.enums.AfsEnumUtil;
import com.ruicar.afs.cloud.common.core.exception.AfsBaseException;
import com.ruicar.afs.cloud.common.core.security.vo.RoleVo;
import com.ruicar.afs.cloud.common.core.util.IResponse;
import com.ruicar.afs.cloud.workflow.api.dto.afsprocess.request.AfsFlowQueryRequest;
import com.ruicar.afs.cloud.workflow.api.dto.afsprocess.request.TaskAssignRequest;
import com.ruicar.afs.cloud.workflow.api.dto.afsprocess.response.TaskAssignResponse;
import com.ruicar.afs.cloud.workflow.api.enums.FlowStatus;
import com.ruicar.afs.cloud.workflow.api.util.FlowMappingHelper;
import com.ruicar.afs.cloud.workflow.greatwall.dto.GwtRequest;
import com.ruicar.afs.cloud.workflow.greatwall.entity.AfsGreatWallTaskAssignInfo;
import com.ruicar.afs.cloud.workflow.greatwall.entity.AfsGreatWallWorkflowBizData;
import com.ruicar.afs.cloud.workflow.greatwall.entity.AfsGreatWallWorkflowMappingInfo;
import com.ruicar.afs.cloud.workflow.greatwall.enums.GwtMsgType;
import com.ruicar.afs.cloud.workflow.greatwall.enums.GwtObjectCode;
import com.ruicar.afs.cloud.workflow.greatwall.enums.RequestPath;
import com.ruicar.afs.cloud.workflow.greatwall.mapper.AfsGreatWallTaskAssignInfoMapper;
import com.ruicar.afs.cloud.workflow.greatwall.processor.GwfObjectCodeProcessor;
import com.ruicar.afs.cloud.workflow.greatwall.service.AfsGreatWallWorkflowBizDataService;
import com.ruicar.afs.cloud.workflow.greatwall.service.AfsGreatWallWorkflowMappingInfoService;
import com.ruicar.afs.cloud.workflow.greatwall.service.AfsGreatWallWorkflowNoticeExceptionService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.text.MessageFormat;
import java.util.List;
import java.util.stream.Collectors;

import static com.ruicar.afs.cloud.workflow.api.constant.FlowConstant.FLOW_EXCEPTION_DESC_KEY;

/**
 * The type TaskAssignNoticeProcessor
 * <p>Description: </p>
 *
 * @author Fzero
 * @version 1.0
 * @date Created on 2020.07.10 21:22:46
 * @since 1.0
 */
@Component
@Slf4j
public class TaskAssignNoticeProcessor extends AbsGwfNoticeProcessor implements GwfObjectCodeProcessor {
    /**
     * Afs great wall workflow mapping info service
     * <p>Description: </p>
     */
    private final AfsGreatWallWorkflowMappingInfoService afsGreatWallWorkflowMappingInfoService;

    private final AfsRoleFeign afsRoleFeign;
    /**
     * Dynamic request
     * <p>Description: </p>
     */
    private final DynamicRequest dynamicRequest;

    private final AfsGreatWallTaskAssignInfoMapper afsGreatWallTaskInfoMapper;

    public TaskAssignNoticeProcessor(AfsGreatWallWorkflowBizDataService afsGreatWallWorkflowBizDataService, AfsGreatWallWorkflowNoticeExceptionService afsGreatWallWorkflowNoticeExceptionService, AfsGreatWallWorkflowMappingInfoService afsGreatWallWorkflowMappingInfoService, DynamicRequest dynamicRequest, AfsGreatWallTaskAssignInfoMapper afsGreatWallTaskInfoMapper,AfsRoleFeign afsRoleFeign) {
        super(afsGreatWallWorkflowBizDataService, afsGreatWallWorkflowNoticeExceptionService);
        this.afsGreatWallWorkflowMappingInfoService = afsGreatWallWorkflowMappingInfoService;
        this.dynamicRequest = dynamicRequest;
        this.afsGreatWallTaskInfoMapper = afsGreatWallTaskInfoMapper;
        this.afsRoleFeign = afsRoleFeign;
    }

    /**
     * Process key string
     *
     * @return the string
     */
    @Override
    public String processKey() {
        return MessageFormat.format("{0}-{1}", AfsEnumUtil.key(belongMsg()), AfsEnumUtil.key(objectCode()));
    }

    /**
     * Belong msg gwt msg type
     *
     * @return the gwt msg type
     */
    @Override
    public GwtMsgType belongMsg() {
        return GwtMsgType.PUSH_DATA;
    }

    /**
     * Object code gwt object code
     *
     * @return the gwt object code
     */
    @Override
    public GwtObjectCode objectCode() {
        return GwtObjectCode.TASK_ASSIGN;
    }

    /**
     * Process string
     *
     * @param request request
     * @return the string
     */
    @Override
    public String process(GwtRequest request) {
        log.info("任务分配通知{}", request);
        AfsGreatWallWorkflowBizData afsGreatWallWorkflowBizData = afsGreatWallWorkflowBizDataService.getBizDataObjServiceIdAndDataId(request.getServiceId(), request.getDataId());
        AfsGreatWallWorkflowMappingInfo afsGreatWallWorkflowMappingInfo = afsGreatWallWorkflowMappingInfoService.queryMappingByServiceId(request.getServiceId());
        if (afsGreatWallWorkflowBizDataService.exception(request.getServiceId(), request.getDataId())) {
            TaskAssignRequest taskAssignRequest = JSON.parseObject(request.getBody(), TaskAssignRequest.class);
            taskAssignRequest.setServiceId(request.getServiceId());
            taskAssignRequest.setBizDataId(request.getDataId());
            taskAssignRequest.setAfsFlowKey(FlowMappingHelper.getAfsKey(request.getServiceId()));
            if (afsGreatWallWorkflowBizData != null) {
                saveException(request, afsGreatWallWorkflowBizData.getFlowInstanceId(), (genExceptionCheckCode(MessageFormat.format("{0}-{1}-{2}", request.getServiceId(), request.getDataId(), taskAssignRequest.getId()))));
            }
            ThreadUtil.execute(new SaveTaskAssign(request.getServiceId(), request.getDataId(), afsGreatWallTaskInfoMapper, taskAssignRequest));
            return bizError;
        }
        TaskAssignResponse taskAssignResponse = new TaskAssignResponse();
        try {
            if (afsGreatWallWorkflowMappingInfo != null) {
                if (noticeBiz(request, afsGreatWallWorkflowMappingInfo)) {
                    taskAssignResponse.setSuccess(true);
                } else {
                    saveError(request, afsGreatWallWorkflowBizData);
                    taskAssignResponse.setSuccess(false);
                }
            } else {
                throw new AfsBaseException("通知数据失败");
            }
        } catch (Exception e) {
            saveError(request, afsGreatWallWorkflowBizData);
            throw e;
        }
        return JSONObject.toJSONString(taskAssignResponse);
    }

    private void saveError(GwtRequest request, AfsGreatWallWorkflowBizData afsGreatWallWorkflowBizData) {
        if (afsGreatWallWorkflowBizData != null) {
            TaskAssignRequest taskAssignRequest = JSON.parseObject(request.getBody(), TaskAssignRequest.class);
            saveException(request, afsGreatWallWorkflowBizData.getFlowInstanceId(), (genExceptionCheckCode(MessageFormat.format("{0}-{1}-{2}", request.getServiceId(), request.getDataId(), taskAssignRequest.getId()))));
            afsGreatWallWorkflowBizData.setFlowStatus(FlowStatus.ERROR);
            String bizData="{}";
            if(StringUtils.isNotEmpty(afsGreatWallWorkflowBizData.getBizData())){
                bizData = afsGreatWallWorkflowBizData.getBizData();
            }
            JSONObject bizDataJson = JSONObject.parseObject(bizData);
            bizDataJson.put(FLOW_EXCEPTION_DESC_KEY,"业务端分配处理人异常");
            afsGreatWallWorkflowBizData.setBizData(bizDataJson.toJSONString());
            afsGreatWallWorkflowBizDataService.updateById(afsGreatWallWorkflowBizData);
        }
    }

    @Override
    public boolean processError(GwtRequest request) {
        AfsGreatWallWorkflowMappingInfo afsGreatWallWorkflowMappingInfo = afsGreatWallWorkflowMappingInfoService.queryMappingByServiceId(request.getServiceId());
        if (afsGreatWallWorkflowMappingInfo != null) {
            try {
                return noticeBiz(request, afsGreatWallWorkflowMappingInfo);
            } catch (Exception e) {
                return false;
            }
        } else {
            return false;
        }
    }

    private boolean noticeBiz(GwtRequest request, AfsGreatWallWorkflowMappingInfo afsGreatWallWorkflowMappingInfo) {
        try {
            TaskAssignRequest taskAssignRequest = JSON.parseObject(request.getBody(), TaskAssignRequest.class);
            AfsFlowQueryRequest<TaskAssignRequest> afsFlowQueryRequest = new AfsFlowQueryRequest<>();
            afsFlowQueryRequest.setData(taskAssignRequest);
            afsFlowQueryRequest.setAfsFlowKey(afsGreatWallWorkflowMappingInfo.getAfsFlowKey());
            taskAssignRequest.setServiceId(request.getServiceId());
            taskAssignRequest.setBizDataId(request.getDataId());
            if(StringUtils.isNotEmpty(taskAssignRequest.getUserName())&&taskAssignRequest.getUserName().startsWith(SecurityConstants.ROLE)){
               String roleName = roleName(taskAssignRequest.getUserName());
               taskAssignRequest.setUserRealName(StringUtils.isEmpty(roleName)?taskAssignRequest.getUserRealName():roleName);
            }
            taskAssignRequest.setAfsFlowKey(FlowMappingHelper.getAfsKey(request.getServiceId()));
            ThreadUtil.execute(new SaveTaskAssign(request.getServiceId(), request.getDataId(), afsGreatWallTaskInfoMapper, taskAssignRequest));
            IResponse<TaskAssignResponse> response =
                    dynamicRequest.post(afsGreatWallWorkflowMappingInfo.getServiceName(), AfsEnumUtil.key(RequestPath.TASK_ASSIGN), afsFlowQueryRequest, new TypeReference<TaskAssignResponse>() {
                    });
            return CommonConstants.SUCCESS.equalsIgnoreCase(response.getCode()) && response.getData().isSuccess();
        } catch (Exception e) {
            log.error("", e);
            throw e;
        }
    }

    private String roleName(String roleName){
        try {
            List<RoleVo> find = afsRoleFeign.getAllList().getData().stream().filter(roleVo -> roleVo.getRoleCode().equals(roleName)).collect(Collectors.toList());
            if(find.size() == 1){
                return find.get(0).getRoleName();
            }else {
                return null;
            }
        }catch (Exception e){
            return null;
        }
    }
    @Slf4j
    private static class SaveTaskAssign implements Runnable {
        private String serviceId;
        private String bizDataId;
        private AfsGreatWallTaskAssignInfoMapper afsGreatWallTaskInfoMapper;
        private TaskAssignRequest taskAssignRequest;

        public SaveTaskAssign(String serviceId, String bizDataId, AfsGreatWallTaskAssignInfoMapper afsGreatWallTaskInfoMapper, TaskAssignRequest taskAssignRequest) {
            this.serviceId = serviceId;
            this.bizDataId = bizDataId;
            this.afsGreatWallTaskInfoMapper = afsGreatWallTaskInfoMapper;
            this.taskAssignRequest = taskAssignRequest;
        }

        @Override
        public void run() {
            if (afsGreatWallTaskInfoMapper.selectCount(Wrappers.<AfsGreatWallTaskAssignInfo>lambdaQuery().eq(AfsGreatWallTaskAssignInfo::getAssignId, taskAssignRequest.getId())) > 0) {
                log.warn("分配记录{}已保存", taskAssignRequest.getId());
                return;
            }
            log.info("保存任务分配信息{},{}", this.serviceId, this.bizDataId);
            AfsGreatWallTaskAssignInfo afsGreatWallTaskAssignInfo = new AfsGreatWallTaskAssignInfo();
            afsGreatWallTaskAssignInfo.setAfsFlowKey(taskAssignRequest.getAfsFlowKey());
            afsGreatWallTaskAssignInfo.setFlowInstanceId(taskAssignRequest.getFlowInstanceId());
            afsGreatWallTaskAssignInfo.setBizDataId(bizDataId);
            afsGreatWallTaskAssignInfo.setFlowServiceId(serviceId);
            afsGreatWallTaskAssignInfo.setNodeId(taskAssignRequest.getTaskNodeId());
            afsGreatWallTaskAssignInfo.setAssignId(taskAssignRequest.getId());
            afsGreatWallTaskAssignInfo.setTaskId(taskAssignRequest.getTaskInstanceId());
            afsGreatWallTaskAssignInfo.setAssignName(taskAssignRequest.getUserName());
            afsGreatWallTaskAssignInfo.setNodeName(taskAssignRequest.getTaskName());
            afsGreatWallTaskInfoMapper.insert(afsGreatWallTaskAssignInfo);
        }
    }
}
